// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

namespace zen {

struct JobId
{
	uint64_t Id = 0;
};

class JobQueue;

class JobContext
{
public:
	virtual bool IsCancelled() const														   = 0;
	virtual void ReportMessage(std::string_view Message)									   = 0;
	virtual void ReportProgress(std::string_view CurrentOp, uint32_t CurrentOpPercentComplete) = 0;
};

class JobQueue
{
public:
	typedef std::function<void(JobContext& Context)> JobFunction;
	virtual ~JobQueue() = default;

	virtual JobId QueueJob(std::string_view Name, JobFunction&& JobFunc) = 0;
	virtual bool  CancelJob(JobId Id)									 = 0;
	virtual void  Stop()												 = 0;

	enum class Status : uint32_t
	{
		Queued,
		Running,
		Aborted,
		Completed
	};

	struct State
	{
		std::string				 CurrentOp;
		uint32_t				 CurrentOpPercentComplete = 0;
		std::vector<std::string> Messages;
		std::string				 AbortReason;
	};

	struct JobInfo
	{
		JobId  Id;
		Status Status;
	};

	virtual std::vector<JobInfo> GetJobs() = 0;

	struct JobDetails
	{
		std::string							  Name;
		Status								  Status;
		State								  State;
		std::chrono::system_clock::time_point CreateTime;
		std::chrono::system_clock::time_point StartTime;
		std::chrono::system_clock::time_point EndTime;
		int									  WorkerThreadId;
	};

	// Will only respond once when status is Complete or Aborted
	virtual std::optional<JobDetails> Get(JobId Id) = 0;

	static std::string_view ToString(Status Status);
};

std::unique_ptr<JobQueue> MakeJobQueue(int WorkerCount, std::string_view QueueName);

void jobqueue_forcelink();

}  // namespace zen
